package com.atguigu.excecise2;

import java.util.concurrent.locks.ReentrantLock;

/**
 * 高内聚 低耦合
 * 资源类：封装卖票的方法,由多个线程来调用
 */
class Tickets {
    //数据  票数量     不能超卖(数量不能为负数)
    private int num = 100;

//创建可重入的排他锁  默认：非公平锁

    private ReentrantLock lock = new ReentrantLock();

    //sync = fair ? new FairSync() : new NonfairSync();
    //private ReentrantLock lock = new ReentrantLock(true); // fair=true 公平锁   默认 fair=false 非公平锁

    /**
     * 卖票方法
     * 使用JUC提供的ReentrantLock
     */
    public void sale() {
        //卖出一张    ++ -- 不是线程安全。
        lock.lock();
        if (num <= 0) {
            System.out.println("票已售罄!");
            lock.unlock();
            return;
        }
//        try {
//            Thread.sleep(1000);
            System.out.println(Thread.currentThread().getName() + "\t" + "窗口开始卖票");
            num--;
//            Thread.sleep(1000);
            System.out.println(Thread.currentThread().getName() + "\t" + "窗口已售出,剩余票数:" + num);
            check();
//        } catch (InterruptedException e) {
//                e.printStackTrace();
//        } finally {
            lock.unlock();
//        }
    }

    /**
     * 为了测试可重入锁，添加检查余票方法
     */

    public void check() {
        lock.lock();
        System.out.println("正在检测...");
        lock.unlock();
    }
}

/**
 * 卖票应用程序：
 * <p>
 * 多线程编程代码模板(上)
 * 高内聚 低耦合
 * 线程 操作 资源类
 */
public class TicketDemo {

    public static void main(String[] args) {

        //资源对象
        Tickets tickets = new Tickets();

        //三个窗口同时卖20张票。
        //模拟卖票窗口
        new Thread(() -> {
            for (int i = 0; i < 50; i++) {
                tickets.sale();
            }
        }, "A").start();
        //模拟卖票窗口
        new Thread(() -> {
            for (int i = 0; i < 50; i++) {
                tickets.sale();
            }
        }, "B").start();
        //模拟卖票窗口
        new Thread(() -> {
            for (int i = 0; i < 50; i++) {
                tickets.sale();
            }
        }, "C").start();
    }
}